package org.dinnermate.unused;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.dinnermate.db.DBManager;

import net.java.ao.DBParam;
import net.java.ao.Entity;

/**
 * This class wraps around a database entity (active object). Since the active object can't have any
 * logic functions, only getters and setters, we use this class to wrap the active object.
 * 
 * @author Jeff
 * 
 * @param <T>
 */
public abstract class DBWrapper<T extends Entity>
{
	protected T ao;
	protected Class<T> type;
	protected boolean isAlive;

	/**
	 * Create an new active object wrapper
	 * 
	 * @param type
	 *            The active objects type to wrap
	 * @param key
	 *            The active objects key
	 */
	public DBWrapper( Class<T> type, int key )
	{
		this.ao = DBManager.getEntityManager().get(type, key);
		this.type = type;
		this.isAlive = (ao != null);
	}

	/**
	 * Create a new new active object wrapper
	 * 
	 * @param ao
	 *            The active object to wrap
	 */
	@SuppressWarnings("unchecked")
	public DBWrapper( T ao )
	{
		this.ao = ao;
		this.type = (Class<T>) ao.getClass();
		this.isAlive = true;
	}

	/**
	 * Create a new active object wrapper
	 * 
	 * @param type
	 *            The active object type to wrap
	 * @param params
	 *            The initial values to insert
	 * @throws SQLException
	 *             Thrown if object could not be inserted into the database
	 */
	public DBWrapper( Class<T> type, DBParam... params ) throws SQLException
	{
		this.ao = DBManager.getEntityManager().create(type, params);
		this.type = type;
		this.isAlive = (ao != null);
	}

	/**
	 * Get the active object
	 * 
	 * @return Active Object
	 * @see Entity
	 */
	public T getAO()
	{
		return ao;
	}

	/**
	 * Get the active object type
	 * 
	 * @return
	 */
	public Class<T> getAOType()
	{
		return type;
	}

	/**
	 * @see RawEntity#save()
	 */
	public void save()
	{
		ao.save();
	}

	/**
	 * Delete object in database
	 * 
	 * @throws SQLException
	 */
	public void delete() throws SQLException
	{
		DBManager.getEntityManager().delete(ao);
		isAlive = false;
	}

	/**
	 * @see Entity#getID()
	 * @return Active objects key in table
	 */
	public int getID()
	{
		return ao.getID();
	}

	/**
	 * If this works: wow I'm good! -- Jeff
	 * 
	 * @param <T>
	 *            Input entity type
	 * @param <K>
	 *            Output object type
	 * @param inputEntitys
	 * @param outputType
	 * @return Array of converted entitys
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Entity, K extends DBWrapper<T>> K[] convertEntitys( T[] inputEntitys,
			Class<K> outputType )
	{
		K[] outputObjects = (K[]) Array.newInstance(outputType, inputEntitys.length);

		Constructor<K> construct = null;
		try
		{
			construct = outputType.getConstructor(inputEntitys[0].getEntityType());
		}
		catch (SecurityException e)
		{
			Logger.getLogger("org.dinnermate.db").log(Level.SEVERE,
					"SecurityException", e.getCause());
		}
		catch (NoSuchMethodException e)
		{
			Logger.getLogger("org.dinnermate.db").log(Level.SEVERE,
					"NoSuchMethodException", e.getCause());
		}
		finally
		{
			if (construct == null) return null;
		}

		for (int x = 0; x < inputEntitys.length; x++)
		{
			try
			{
				outputObjects[x] = construct.newInstance(inputEntitys[x]);
			}
			catch (IllegalArgumentException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (InstantiationException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (IllegalAccessException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (InvocationTargetException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return outputObjects;
	}
}
